package com.jsm.twentyfour.service;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jsm.twentyfour.cache.BaseDTOCacheClient;
import com.jsm.twentyfour.domain.BaseDomain;
import com.jsm.twentyfour.dto.BaseDTO;
import com.jsm.twentyfour.exception.BusinessException;
import com.jsm.twentyfour.mapper.BaseMapper;
import com.jsm.twentyfour.util.UniqueDBIndexUtil;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * create by jsm on 2018/4/25
 */
//D:数据库实体类  BaseDomain: 由于id不自增需要自行设置,所以需要继承 DTO：实体类对应的DTO  BaseDTO:带有一个exist字段 用于缓存防击穿  Ex:对应的Example
@Service

public abstract class BaseService<D extends BaseDomain, DTO extends BaseDTO, Ex> {
    @Resource
    private BaseDTOCacheClient baseDTOCacheClient;
    @Value("${application.cacheable}")
    private boolean cacheable;
    public DTO getById(Long id) {
        try {
            if (cacheClient() != null) {
                DTO dto = cacheClient().get(id, getDTOClass());
                if (dto != null) {
                    if (dto.getExist() != null && dto.getExist().booleanValue() == false) {
                        return null;
                    } else {
                        return dto;
                    }
                } else {
                    return get(id);
                }
            } else {
                return get(id);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("sys error");
        }
    }

    private DTO get(Long id) throws IllegalAccessException, InstantiationException {
        D d = mapper().selectByPrimaryKey(id);
        if (d == null && cacheClient() != null) {
            DTO dto = getDTOClass().newInstance();
            dto.setId(id);
            dto.setExist(false);
            cacheClient().put(dto);
            return null;
        } else {
            DTO ret = transfer(d);
            if (cacheClient() != null) {
                cacheClient().put(ret);
            }
            return ret;
        }
    }

    public DTO insertSelective(D d) {
        //由于ID不是自增 所有domain都需要继承BaseDomain
        d.setId(UniqueDBIndexUtil.generate());
        int insert = mapper().insertSelective(d);

        DTO dto = transfer(d);
        if (insert > 0 && cacheClient() != null) {
            dto = getById(d.getId());
            cacheClient().put(dto);
        }
        return dto;
    }

    public int updateSelective(D d) {
        try {
            int update = mapper().updateByPrimaryKeySelective(d);

            if (update > 0 && cacheClient() != null) {
                DTO dto = get(d.getId());
                cacheClient().put(dto);
            }
            return update;
        } catch (Exception e) {
            e.printStackTrace();
            BusinessException.throwException("服务器开小差了~~~");
        }
        return 0;

    }

    public List <DTO> listByExample(Ex example, int page, int pageSize) {
        List <DTO> ret = new ArrayList <>();
        if (page > 0 && pageSize > 0) {
            Page <Object> pageInfo = PageHelper.startPage(page, pageSize);
        }
        List <D> ds = mapper().selectByExample(example);
        if (ds != null && ds.size() > 0) {
            ds.forEach(d -> ret.add(transfer(d)));
            return ret;
        } else {
            return null;
        }
    }


    @Data
    static public class PageList<T> {
        private List <T> list;
        private int total;
    }

    public PageList <DTO> pagelistByExample(Ex example, int page, int pageSize) {
        PageList <DTO> pageList = new PageList <>();
        List <DTO> ret = new ArrayList <>();
        Page <Object> pageInfo = null;
        if (page > 0 && pageSize > 0) {
            pageInfo = PageHelper.startPage(page, pageSize);
        }
        List <D> ds = mapper().selectByExample(example);
        if (ds != null && ds.size() > 0) {
            ds.forEach(d -> ret.add(transfer(d)));
            pageList.setList(ret);
            if (pageInfo != null) {
                pageList.setTotal((int) pageInfo.getTotal());
            }
            return pageList;
        } else {
            return pageList;
        }
    }

    public DTO getByExample(Ex example) {
        PageHelper.startPage(1, 1);
        List <D> ds = mapper().selectByExample(example);
        if (ds != null && ds.size() > 0) {
            return transfer(ds.get(0));
        } else {
            return null;
        }
    }

    //所有Mapper都应继承BaseMapper
    public abstract BaseMapper <D, Ex> mapper();



    //获取缓存客户端
    public BaseDTOCacheClient <DTO> cacheClient() {
        if (cacheable) {
            return baseDTOCacheClient;
        } else {
            return null;
        }


    }


    //获取DTO类
    public abstract Class <DTO> getDTOClass();

    //D转化成DTO的方法
    public abstract DTO transfer(D d);

    public int delete(Long id) {
        if (cacheClient() != null) {
            cacheClient().remove(id, getDTOClass());
        }
        return mapper().deleteByPrimaryKey(id);
    }

    public int deleteByExample(Ex ex) {
        return mapper().deleteByExample(ex);
    }

    public int countByExample(Ex ex) {
        return (int) mapper().countByExample(ex);
    }

    public int updateByExample(D d, Ex ex) {
        if (cacheClient() != null) {
            List <DTO> dtos = listByExample(ex, 0, 0);
            if (dtos != null && dtos.size() > 0) {
                dtos.forEach(dto -> cacheClient().remove(dto));
            }
        }
        return mapper().updateByExample(d, ex);
    }

    public int updateByExampleSelective(D d, Ex ex) {
        if (cacheClient() != null) {
            List <DTO> dtos = listByExample(ex, 0, 0);
            if (dtos != null && dtos.size() > 0) {
                dtos.forEach(dto -> cacheClient().remove(dto));
            }
        }
        return mapper().updateByExampleSelective(d, ex);
    }
}
